package com.brillilab.service.logic.file;

import com.aliyun.openservices.shade.org.apache.commons.lang3.StringUtils;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.PutObjectResult;
import com.brillilab.common.alioss.OssFileEnum;
import com.brillilab.common.alioss.OssUtils;
import com.brillilab.common.utils.FileSecurityUtil;
import com.brillilab.domain.enums.file.UploadStausEnum;
import com.brillilab.domain.po.experiments.Experiment;
import com.brillilab.domain.po.system.FileManage;
import com.brillilab.domain.po.topics.Topic;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.experiments.IExperimentService;
import com.brillilab.service.core.system.IFileManageService;
import com.brillilab.service.core.topics.ITopicDirectionService;
import com.brillilab.service.core.topics.ITopicExperimentService;
import com.brillilab.service.core.topics.ITopicService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.io.*;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @author zlb
 * @Title: FileManageLogic
 * @ProjectName brill_lab
 * @Description: TODO
 * @date 2019/6/14 10:31
 */
@Service
@Slf4j
@Transactional
public class FileManageLogic {

    @Resource
    private OssUtils ossUtil;

    @Resource
    private IExperimentService experimentService;

    @Resource
    private IFileManageService fileManageService;

    @Resource
    private ITopicService topicService;

    @Resource
    private ITopicDirectionService topicDirectionService;

    @Resource
    private ITopicExperimentService topicExperimentService;

    /**
     * 初始化文件上传数据
     * @param attachType   附件ID
     * @param labId        实验室Id
     * @param referDataId  业务关联ID
     * @param origFileName 文件名
     * @param fileType     文件类型
     * @param MimeType     内容类型
     * @param fileSize     文件大小（字节）
     * @return
     */
    public FileManage initFileManage(Integer attachType, Long labId, Long referDataId, String origFileName, Integer fileType, String MimeType, Long fileSize) {
        String bucketName = ossUtil.getBucketName(attachType);
        FileManage fileManage = new FileManage();
        fileManage.setBucketName(bucketName);
        fileManage.setAttachType(attachType);
        fileManage.setReferDataId(referDataId);
        fileManage.setLabId(labId);
        fileManage.setUploadStatus(UploadStausEnum.Uploading.getValue());
        fileManage.setName(origFileName);
        fileManage.setFileType(fileType);
        fileManage.setMimeType(MimeType);
        fileManage.setSize(fileSize);
        return fileManageService.insert(fileManage);
    }

    /**
     * 执行文件上传
     *
     * @param attachType   附件类型
     * @param origFileName 文件名
     * @param fileStream   文件流
     * @param fileManage   文件类
     * @param userInfo     用户信息
     * @return
     * @throws IOException
     */
    public Map<String, Object> uploadFile(Integer attachType, String origFileName, InputStream fileStream, FileManage fileManage, UserInfoVo userInfo) throws IOException {
        Map<String, Object> resMap = new LinkedHashMap<>();
        Assert.notNull(fileManage, "文件管理信息为空！");
        String bucketName = ossUtil.getBucketName(attachType);
        String basePath = "";
        if (OssFileEnum.PersonHeadImg.getKey().equals(attachType)) {
            //头像-公共
            basePath = ossUtil.getFileBasePath(attachType, userInfo.getId());
        } else if (OssFileEnum.Method.getKey().equals(attachType)) {
            //方法-个人
            basePath = ossUtil.getFileBasePath(attachType, userInfo.getId());
        } else {
            //其它-实验室
            Assert.notNull(userInfo.getLabId(), "用户未加入实验室！");
            basePath = ossUtil.getFileBasePath(attachType, userInfo.getLabId());
        }
        //避免文件被覆盖，objectKey的命名可以结合时间戳
//        String imageName=origFileName.substring(0,origFileName.lastIndexOf("."));
//        String perfix=imageName + "_" + new Date().getTime();
//        String suffix=origFileName.substring(origFileName.lastIndexOf(".") + 1);
//        String fileName=perfix + "." + suffix;

        String objectName = basePath + origFileName;
        boolean isEncrypt = false;//文件是否加密
        InputStream uploadStream = fileStream;
        //实验结果和课题附件须要加密上传
        if (attachType >= OssFileEnum.AnalyzeDataFile.getKey() && attachType <= OssFileEnum.AnalyzeDataFileThumbnail.getKey()) {
            //实验结果文件加密
            if (fileManage.getReferDataId() > 0 && OssFileEnum.getIsEncrypt(attachType)) {
                //获取实验结果信息
                Experiment experiment = experimentService.selectById(fileManage.getReferDataId().longValue());
                if (experiment != null) {
                    Topic topic = topicService.selectById(experiment.getTopicId());
                    if (topic != null && StringUtils.isNotBlank(topic.getFileSecretKey())) {
                        uploadStream = FileSecurityUtil.encryptInputStream(fileStream, topic.getFileSecretKey());
                        isEncrypt = true;
                    }
                }
            }
        } else if (attachType >= 500 && attachType < 600) {
            //课题文件加密
            Long topicId = 0l;
            if (fileManage.getReferDataId() > 0 && OssFileEnum.getIsEncrypt(attachType)) {
                topicId = fileManage.getReferDataId();
                Topic topic = topicService.selectById(topicId);
                if (topic != null && StringUtils.isNotBlank(topic.getFileSecretKey())) {
                    uploadStream = FileSecurityUtil.encryptInputStream(fileStream, topic.getFileSecretKey());
                    isEncrypt = true;
                }
            }
        }

        OSSClient ossClient = ossUtil.initClient();
        PutObjectResult result = OssUtils.uploadByInputStream(ossClient, uploadStream, bucketName, objectName);
        String filePath = objectName;
        if (result != null && !StringUtils.isEmpty(result.getETag())) {
            //logger.info("uploadResult:" + JSON.toJSONString(result));
            resMap.put("attachId", fileManage.getId());
            resMap.put("name", origFileName);
            resMap.put("size", fileManage.getSize());

            if (OssFileEnum.getIsPublicBucket(attachType)) {
                //公共存储空间返回访问全地址
                filePath = ossUtil.getHostUrl(attachType) + objectName;
            }

            resMap.put("bucketName", fileManage.getBucketName());
            resMap.put("path", filePath);
            fileManage.setPath(filePath);
            fileManage.setUploadStatus(UploadStausEnum.Uploaded.getValue());
            fileManage.setIsEncrypt(isEncrypt);
            fileManage.setUpdateTime(new Date());
            fileManage.setCallbackTime(new Date());
            fileManage.setUserId(userInfo.getId());

            boolean b = fileManageService.updateById(fileManage);
            return b ? resMap : null;
        } else {
            //上传失败
            return null;
        }
    }

    /**
     * 保存文件
     *
     * @param inputStream
     * @param path
     * @param fileName
     */
    private void saveFile(InputStream inputStream, String path, String fileName) {
        OutputStream os = null;
        try {
            // 1、保存到临时文件
            // 1K的数据缓冲
            byte[] bs = new byte[1024];
            // 读取到的数据长度
            int len;
            // 输出的文件流保存到本地文件

            File tempFile = new File(path);
            if (!tempFile.exists()) {
                tempFile.mkdirs();
            }
            os = new FileOutputStream(tempFile.getPath() + File.separator + fileName);
            // 开始读取
            while ((len = inputStream.read(bs)) != -1) {
                os.write(bs, 0, len);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 完毕，关闭所有链接
            try {
                os.close();
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }


    /**
     * 执行文件上传
     *
     * @param attachType   附件类型
     * @param origFileName 文件名
     * @param fileStream   文件流
     * @param fileManage   文件类
     * @param userInfo     用户信息
     * @return
     * @throws IOException
     */
    public Map<String, Object> uploadFileNoToken(Integer attachType, Long referDataId, String origFileName, InputStream fileStream, FileManage fileManage) throws IOException {
        Map<String, Object> resMap = new LinkedHashMap<>();
        Assert.notNull(fileManage, "文件管理信息为空！");
        String bucketName = ossUtil.getBucketName(attachType);
        //Assert.isTrue(OssFileEnum.CertificateImg.getKey().equals(attachType), "附件类型有误！");
        String basePath = ossUtil.getFileBasePath(attachType, referDataId);
        //避免文件被覆盖，objectKey的命名可以结合时间戳
        String imageName = origFileName.substring(0, origFileName.lastIndexOf("."));
        String prefix = imageName + "_" + new Date().getTime();
        String suffix = origFileName.substring(origFileName.lastIndexOf(".") + 1);
        String fileName = prefix + "." + suffix;

        String objectName = basePath + fileName;
        OSSClient ossClient = ossUtil.initClient();
        PutObjectResult result = OssUtils.uploadByInputStream(ossClient, fileStream, bucketName, objectName);
        String filePath = objectName;
        if (result != null && !StringUtils.isEmpty(result.getETag())) {
            //logger.info("uploadResult:" + JSON.toJSONString(result));
            resMap.put("attachId", fileManage.getId());
            resMap.put("name", origFileName);
            resMap.put("size", fileManage.getSize());
            resMap.put("imgUrl", ossUtil.getAccessUrl(ossClient, bucketName, objectName));

            //公有空间直接返回全地址
            if (OssFileEnum.PersonHeadImg.getKey().equals(attachType) || OssFileEnum.VideoPreviewImg.getKey().equals(attachType)
                    || OssFileEnum.PublicMethod.getKey().equals(attachType) || OssFileEnum.PublicFile.getKey().equals(attachType) || OssFileEnum.LabLogo.getKey().equals(attachType)) {
                filePath = ossUtil.getHostUrl(attachType) + objectName;
            }
            resMap.put("bucketName", fileManage.getBucketName());
            resMap.put("path", filePath);
            fileManage.setPath(filePath);
            fileManage.setUploadStatus(UploadStausEnum.Uploaded.getValue());
            fileManage.setIsEncrypt(false);
            fileManage.setUpdateTime(new Date());
            fileManage.setCallbackTime(new Date());

            boolean b = fileManageService.updateById(fileManage);
            return b ? resMap : null;
        } else {
            //上传失败
            return null;
        }
    }
}
